import com.smartfoxserver.v2.SmartFox;
import com.smartfoxserver.v2.core.SFSEvent;
import com.smartfoxserver.v2.entities.Room;
import com.smartfoxserver.v2.entities.SFSRoom;
import com.smartfoxserver.v2.entities.managers.SFSRoomManager;
import com.smartfoxserver.v2.redbox.AVCastManager;
import com.smartfoxserver.v2.redbox.data.LiveCast;
import com.smartfoxserver.v2.redbox.events.RedBoxCastEvent;
import com.smartfoxserver.v2.redbox.events.RedBoxConnectionEvent;
import com.smartfoxserver.v2.requests.CreateRoomRequest;
import com.smartfoxserver.v2.requests.JoinRoomRequest;
import com.smartfoxserver.v2.requests.LoginRequest;
import com.smartfoxserver.v2.requests.LogoutRequest;
import com.smartfoxserver.v2.requests.PrivateMessageRequest;
import com.smartfoxserver.v2.requests.PublicMessageRequest;
import com.smartfoxserver.v2.requests.RoomSettings;
import com.smartfoxserver.v2.util.ClientDisconnectionReason;

import components.Broadcast;
import components.CreateSpeachPanel;
import components.LoginPanel;
import components.SpeachPanel;
import components.SphereClient;
import components.VideoConferenceItem;

import events.SelectedSpeachChanged;

import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.media.Camera;
import flash.net.NetStream;
import flash.sampler.startSampling;
import flash.utils.setTimeout;

import mx.collections.ArrayCollection;
import mx.containers.HBox;
import mx.controls.Alert;
import mx.controls.Button;
import mx.controls.Label;
import mx.controls.VideoDisplay;
import mx.events.CloseEvent;
import mx.events.ListEvent;
import mx.managers.PopUpManager;

private var sfs:SmartFox;
private var _authorized:Boolean = false;
private var createRoomPanel:CreateSpeachPanel;
private var loginPanel:LoginPanel;
private var speachPanel:SpeachPanel;
private var rooms:Array;
private var alert:Alert;
private var listSource:ArrayCollection = new ArrayCollection();
private var avCastMan:AVCastManager;
//var sphere:SphereClient = new SphereClient();

private function init():void
{
	sfs = new SmartFox(true);
	sfs.addEventListener(SFSEvent.CONNECTION, onConnectionRise);
	sfs.addEventListener(SFSEvent.CONNECTION_LOST, onConnectionLost);
	sfs.addEventListener(SFSEvent.LOGIN, onLogin);
	sfs.addEventListener(SFSEvent.LOGIN_ERROR, onLoginError);
	sfs.addEventListener(SFSEvent.LOGOUT, onLogout);
	sfs.addEventListener(SFSEvent.ROOM_ADD, onRoomAdd);
	sfs.addEventListener(SFSEvent.ROOM_JOIN, onRoomJoin);
	sfs.addEventListener(SFSEvent.ROOM_REMOVE, onRoomRemove);
	sfs.addEventListener(SFSEvent.ROOM_CREATION_ERROR, onRoomCreationError);
	sfs.addEventListener(SFSEvent.USER_COUNT_CHANGE, onUserCountChange);
	sfs.addEventListener(SFSEvent.PUBLIC_MESSAGE, onPublicMessage);
	log("Connecting...");     
	sfs.loadConfig("config/sfs-config.xml");
	
//	myVCItem.setLabelText("(me)");
	
	//add sphere
//	view_sphere.addChild(sphere);
}

private function onConnectionRise(event:SFSEvent):void
{
	if(event.params.success){
		log("Connection Success");	
		sfs.send(new LoginRequest("", "", "SpeakersSphere"));
	}else{
		log("Connection Failed");
	}
}

/**
 * On connection lost, go back to login panel view and display disconnection error message.
 */
private function onConnectionLost(evt:SFSEvent):void
{
	// Remove popup, if any
	removePopUp();
	
	// Remove alert, if displayed
	removeAlert();
	
	// Remove listeners added to AVCastManager instance
	if (avCastMan != null)
	{
		avCastMan.removeEventListener(RedBoxConnectionEvent.AV_CONNECTION_INITIALIZED, onAVConnectionInited);
		avCastMan.removeEventListener(RedBoxConnectionEvent.AV_CONNECTION_ERROR, onAVConnectionError);
		avCastMan.removeEventListener(RedBoxCastEvent.LIVE_CAST_PUBLISHED, onLiveCastPublished);
		avCastMan.removeEventListener(RedBoxCastEvent.LIVE_CAST_UNPUBLISHED, onLiveCastUnpublished);
		avCastMan = null;
	}
	
	// Show disconnection message, unless user chose voluntarily to close the connection
	if (evt.params.reason != ClientDisconnectionReason.MANUAL)
	{
		var msg:String = "Connection lost";
		
		switch (evt.params.reason)
		{
			case ClientDisconnectionReason.IDLE:
				msg += "\nYou have exceeded the maximum user idle time";
				break;
			
			case ClientDisconnectionReason.KICK:
				msg += "\nYou have been kicked";
				break;
			
			case ClientDisconnectionReason.BAN:
				msg += "\nYou have been banned";
				break;
			
			case ClientDisconnectionReason.UNKNOWN:
				msg += " due to unknown reason\nPlease check the server-side log";
				break;
		}
		
		loginPanel.ta_error.text = msg;
	}
	
	// Show login view
//	mainView.selectedChild = view_connecting;
}

private function onLogin(event:SFSEvent):void
{
    removePopUp();
    signInButton.enabled = false;
    signOutButton.enabled = true;
	log("Login Success:" + event.params.user.name);
	mainView.selectedChild = view_sphere;
	showRooms();
	initializeAV();
    createSpeachButton.enabled = _authorized;
}

private function onLoginError(event:SFSEvent):void
{
	log("Login failed: " + event.params.errorMessage);
    loginPanel.ta_error.text = event.params.errorMessage;
    _authorized = false;
}

private function onLogout(event:SFSEvent):void
{
    signInButton.enabled = true;
    signOutButton.enabled = false;
	log("Logout Success");
    cleanRooms();
}

private function log(message:String):void
{
	chatArea.text += message + "\n";
	setTimeout(function():void{chatArea.verticalScrollPosition = chatArea.maxVerticalScrollPosition;},100); 
}

private function showRooms():void
{				
	rooms = sfs.roomList;
	log("Rooms number: " + rooms.length);
	
	for each (var room:SFSRoom in rooms) 
	{
		log("Room '" + room.name + "' (" + room.userCount + "/" + room.capacity + ")");
		
		var item:Object = new Object();
		item.height = 70;
		item.width = 160;
		item.icon = "@Embed('assets/cam.png')";
		item.label = room.name + " (" + room.userCount + "/" + room.capacity + ")";
		item.id = room.id;
		listSource.addItem(item);
		
		
	}	
	roomList.dataProvider = listSource;
	
	/*var i:int = 1;
	for each (var room:SFSRoom in rooms) 
	{
		var br:Broadcast = new Broadcast();
		br.setName(i++);
//		br.setBroadcast(room);				
		//		sphere.addElement();
		sphereContainer.sphereClient.addElement(br);
	}*/
	//update sphere
//	sphere.updateSphere(rooms);
//	sphereContainer.sphereClient.updateSphere(rooms);
	/*for(var i=5; i<10; i++) {
		var b:Broadcast = new Broadcast();
		b.setName(i+1);
		sphereContainer.sphereClient.addElement(b);
	}*/
	
	sphereContainer.sphereClient.updateSphere(rooms);
}

private function cleanRooms():void
{
    listSource.removeAll();    
}

public function loginButton_clickHandler(login:String, password:String):void
{
	log("Login...");
	sfs.send(new LoginRequest(login, password, "SpeakersSphere"));
    _authorized = true;
}

private function onSignInBtClick():void
{
	showLoginPanel();
}

private function showLoginPanel():void
{
	loginPanel = PopUpManager.createPopUp(this, LoginPanel, true) as LoginPanel;
	PopUpManager.centerPopUp(loginPanel);
	loginPanel.addEventListener(CloseEvent.CLOSE, closeLoginPanel, false, 0, true);
}

private function closeLoginPanel():void
{
	if (loginPanel != null)
	{
		loginPanel.removeEventListener(CloseEvent.CLOSE, closeLoginPanel);
		PopUpManager.removePopUp(loginPanel);
		loginPanel = null;
	}
}

private function onSignOutBtClick():void
{
	log("Sign Out...");
	sfs.send(new LogoutRequest());
}

public function logoutButton_clickHandler(event:MouseEvent):void
{
	log("Logout...");
	sfs.send(new LogoutRequest());
}

public function sendButton_clickHandler(event:MouseEvent):void
{
	
}

protected function roomList_itemClickHandler(event:ListEvent):void
{
//	chatArea.text += event.currentTarget.selectedItem.id + "\n";
	joinRoom(event.currentTarget.selectedItem.id);
}

protected function sphereContainer_speachChangedHandler(event:SelectedSpeachChanged):void
{
	joinRoom(event.speachId);
//	showAlert("Selected speach changed: " + event.speachId);
}

public function joinRoom(roomId:int):void
{
	sfs.send(new JoinRoomRequest(roomId));
}

private function onCreateSpeachApplicationBtClick():void
{
	showCreateRoomPanel();
}

private function showCreateRoomPanel():void
{
	createRoomPanel = PopUpManager.createPopUp(this, CreateSpeachPanel, true) as CreateSpeachPanel;
	PopUpManager.centerPopUp(createRoomPanel);
	createRoomPanel.addEventListener(CloseEvent.CLOSE, closeCreateRoomPanel, false, 0, true);
}

private function closeCreateRoomPanel():void
{
	if (createRoomPanel != null)
	{
		createRoomPanel.removeEventListener(CloseEvent.CLOSE, closeCreateRoomPanel);
		PopUpManager.removePopUp(createRoomPanel);
		createRoomPanel = null;
	}
}

private function removePopUp():void
{
    closeCreateRoomPanel();
    closeLoginPanel();    
}

public function onCreateSpeachPopuUpBtClick():void
{
	if (createRoomPanel.ti_roomName.length > 0)
	{
		// Collect room settings
		var settings:RoomSettings = new RoomSettings(createRoomPanel.ti_roomName.text);
		settings.groupId = createRoomPanel.lb_group.text;
		settings.maxUsers = createRoomPanel.ns_maxUsers.value;
		
		// Create room
		var request:CreateRoomRequest = new CreateRoomRequest(settings, true, sfs.lastJoinedRoom);
		sfs.send(request);
		
		// Close popup
		removePopUp();
	}
}

public function onRoomAdd(event:SFSEvent):void
{	
	var item:Object = new Object();
	var room:Room = event.params.room; 
	item.height = 70;
	item.width = 160;
	item.label = room.name + " (" + room.userCount + "/" + room.capacity + ")";
	item.id = room.id;
	listSource.addItem(item);
	
	log("New room added: " + item.label);
	
	//update sphere
	rooms = sfs.roomList;
	sphereContainer.sphereClient.updateSphere(rooms);
}

public function onRoomRemove(event:SFSEvent):void
{	
	var item:Object = new Object();
	var room:Room = event.params.room; 
	item.height = 70;
	item.width = 160;
	item.label = room.name + " (" + room.userCount + "/" + room.capacity + ")";
	item.id = room.id;
	listSource.removeItemAt(listSource.getItemIndex(item));
	
	log("Room removed: " + item.label);
	
	//update sphere
	rooms = sfs.roomList;
	sphereContainer.sphereClient.updateSphere(rooms);
}

public function onRoomCreationError(event:SFSEvent):void
{	
	log("Room creation error: " + event.params.errorMessage);
}


public function onRoomJoin(event:SFSEvent):void
{    
	var room:Room = event.params.room;				
	if(room.userCount == 1)
	{
		log("Joined empty room '" + room.name + "' (" + room.userCount + ")");
        //disable listen buttons
//        bt_startListen.enabled = false;
//        bt_stopListen.enabled = false;
        //enable speak buttons
//        bt_startSpeach.enabled = true;
//        bt_stopSpeach.enabled = true;
//		onStartSpeaking();
	}else{
		log("Joined room " + room.name + " (" + room.userCount + ")");
		//enable listen buttons
//        bt_startListen.enabled = true;
//        bt_stopListen.enabled = true;
        //disable speak buttons
//        bt_startSpeach.enabled = false;
//        bt_stopSpeach.enabled = false;
//        onStartListening();
	}
}

public function onUserCountChange(event:SFSEvent):void
{
	var room:Room = event.params.room; 
	for each (var item:Object in listSource.source) 
	{
		if(item.id == room.id)
		{
			item.label = room.name + " (" + room.userCount + "/" + room.capacity + ")";
			listSource.refresh();
			log(room.name + " capacity changed to " + room.userCount);
		}
	}
}
private function showAlert(message:String):void
{
	// Remove previous alert, if any
	removeAlert();
	
	// Show alert
	alert = Alert.show(message, "Warning", Alert.OK, null, onAlertClosed);
}

private function removeAlert():void
{
	if (alert != null){
		PopUpManager.removePopUp(alert);
	}
	
	alert = null;
}

private function onAlertClosed(evt:Event):void
{
	removeAlert();
}

private function showSpeachWindow():void
{
	speachPanel = PopUpManager.createPopUp(this, SpeachPanel, true) as SpeachPanel;
//	PopUpManager.centerPopUp(speachPanel);
//	speachPanel.addEventListener(CloseEvent.CLOSE, removeSpeachWindow, false, 0, true);
}

/*private function removeSpeachWindow(evt:CloseEvent):void
{
	if (speachPanel != null){
		PopUpManager.removePopUp(speachPanel);
	}

	speachPanel = null;
}*/

/**
 * Start speach
 */
public function onStartSpeach():void
{
    for each (var liveCast:LiveCast in avCastMan.getAvailableCasts())
	{
		log("live cast: " + liveCast.id);
	}
}

/**
 * Start speaking
 */
public function onStartSpeaking():void
{		
	// Publish my live cast
	try
	{
		var myStream:NetStream = avCastMan.publishLiveCast(true, true);
		showSpeachWindow();
		if (myStream != null)
		{
			// Add item to video container
			var myVCItem:VideoConferenceItem = speachPanel.myVCItem;
			myVCItem.name = "user_" + sfs.mySelf.id;
			
			speachPanel.videoContainer.addChild(myVCItem);
			myVCItem.setLabelText("me");
			
			// Attach camera output 
			myVCItem.attachCamera(Camera.getCamera());
			
//			bt_startSpeach.enabled = false;
//			bt_stopSpeach.enabled = true;
		}
	}
	catch (e:Error)
	{
		var error:String = "The following error occurred while trying to subscribe a live cast: " + e.getStackTrace();
		
		// Show alert
		showAlert(error);
	}
}

/**
 * Start listening
 */
public function onStartListening():void
{
    //show speach window
    showSpeachWindow();
	// Retrieve live casts already available
	for each (var liveCast:LiveCast in avCastMan.getAvailableCasts())
	{
		// Subscribe cast
        var stream:NetStream = avCastMan.subscribeLiveCast(liveCast.id);

        if (stream != null)
        {
            var item:VideoConferenceItem = speachPanel.myVCItem;

            // Attach stream to item
            item.setLabelText(liveCast.username);
            item.attachStream(stream);         
        }
	}
}

/**
 * Stop speach
 */
public function onStopSpeach():void
{
    PopUpManager.removePopUp(speachPanel);
	// Stop receiveing cast publish/unpublish notification
	avCastMan.stopPublishNotification();
	
	// Unpublish my live cast
	avCastMan.unpublishLiveCast();
	
	// Reset video conference item
    var myVCItem:VideoConferenceItem = speachPanel.myVCItem;
	myVCItem.reset();

    // Stop receiveing cast publish/unpublish notification
	avCastMan.unsubscribeAllLiveCasts();

    //change buttons state
//    bt_startSpeach.enabled = true;
//	bt_stopSpeach.enabled = false;
}

public function sendPublicMessage(message:String):void
{
    var request:PublicMessageRequest = new PublicMessageRequest(message);
	sfs.send(request);
}

/**
 * On public message, show it in the chat area.
 */
private function onPublicMessage(evt:SFSEvent):void
{
	speachPanel.showChatMessage(evt.params.message, evt.params.sender);
}

/**
 * Initialize the AVChatManager instance.
 */
private function initializeAV():void
{
	// Create AVChatmanager instance
	avCastMan = new AVCastManager(sfs, sfs.currentIp, false, true);
	
	avCastMan.addEventListener(RedBoxConnectionEvent.AV_CONNECTION_INITIALIZED, onAVConnectionInited);
	avCastMan.addEventListener(RedBoxConnectionEvent.AV_CONNECTION_ERROR, onAVConnectionError);
	avCastMan.addEventListener(RedBoxCastEvent.LIVE_CAST_PUBLISHED, onLiveCastPublished);
	avCastMan.addEventListener(RedBoxCastEvent.LIVE_CAST_UNPUBLISHED, onLiveCastUnpublished);

}

//---------------------------------------------------------------------
// RedBox AVCastManager event handlers
//---------------------------------------------------------------------

/**
 * Handle A/V connection initialized.
 */
public function onAVConnectionInited(evt:RedBoxConnectionEvent):void
{
	// Nothing to do. Usually we should wait this event before enabling the a/v chat related interface elements.
	log("AV Connection Inited");
}

/**
 * Handle A/V connection error.
 */
public function onAVConnectionError(evt:RedBoxConnectionEvent):void
{
	var error:String = "The following error occurred while trying to establish an A/V connection: " + evt.params.errorCode;
	
	log(error);
	// Show alert
	showAlert(error);
}

/**
 * Handle new live cast published by user
 */
public function onLiveCastPublished(evt:RedBoxCastEvent):void
{
	var liveCast:LiveCast = evt.params.liveCast;
	
	trace ("User " + liveCast.username + " published his live cast");
	log("User " + liveCast.username + " published his live cast");

    onStartListening();
}

/**
 * Handle live cast unpublished by user
 */
public function onLiveCastUnpublished(evt:RedBoxCastEvent):void
{
	var liveCast:LiveCast = evt.params.liveCast;
	
	trace ("User " + liveCast.username + " unpublished his live cast");
	log("User " + liveCast.username + " unpublished his live cast");
    
    onStopSpeach();
}